﻿using System;
using System.Linq;

namespace Shell.PocoDot.Configurations
{
    /// <summary>
    /// PocoDot 之间的关系的注册处的扩展类
    /// </summary>
    public static class IRelationRegistrarExtensions
    {
        /// <summary>
        /// 注册特定的 PocoDot 之间的关系的配置信息
        /// </summary>
        /// <typeparam name="TMainPocoDot">指定的关系中的主 PocoDot的类型</typeparam>
        /// <typeparam name="TRelatedPocoDot">指定的关系中的从 PocoDot的类型</typeparam>
        /// <param name="configurator">PocoDot 之间的关系的注册处的实例</param>
        /// <param name="relationship">主 PocoDot 到从 PocoDot 之间的映射关系</param>
        /// <param name="reversedRelationship">从 PocoDot 到主 PocoDot 之间的映射关系</param>
        /// <param name="provider">持久化提供器的配置信息</param>
        /// <returns>PocoDot 之间的关系的注册处的实例</returns>
        public static IRelationRegistrar Register<TMainPocoDot, TRelatedPocoDot>(this IRelationRegistrar configurator,
            Relationships relationship, Relationships reversedRelationship,
            ProviderConfiguration provider)
            where TMainPocoDot : PocoDotBase
            where TRelatedPocoDot : PocoDotBase
        {
            var mainType = typeof(TMainPocoDot);
            var relatedType = typeof(TRelatedPocoDot);
            configurator.Register(mainType, relationship, relatedType, reversedRelationship, provider);
            return configurator;
        }

        /// <summary>
        /// 注册特定的 PocoDot 之间的关系的配置信息
        /// </summary>
        /// <param name="configurator">PocoDot 之间的关系的注册处的实例</param>
        /// <param name="mainPocoDot">指定的关系中的主 PocoDot的类型</param>
        /// <param name="relationship">主 PocoDot 到从 PocoDot 之间的映射关系</param>
        /// <param name="relatedPocoDot">指定的关系中的从 PocoDot的类型</param>
        /// <param name="reversedRelationship">从 PocoDot 到主 PocoDot 之间的映射关系</param>
        /// <param name="provider">持久化提供器的配置信息</param>
        /// <returns>PocoDot 之间的关系的注册处的实例</returns>
        public static IRelationRegistrar Register(this IRelationRegistrar configurator,
             Type mainPocoDot, Relationships relationship,
             Type relatedPocoDot, Relationships reversedRelationship,
            ProviderConfiguration provider)
        {
            var configs = PocoDotRegistrar.Registrar.Configurations;
            if (!configs.Any(c => c.PocoDot == mainPocoDot))
            {
                throw new InvalidOperationException(SR.Get("Error.PocoConfigurationNotExist", mainPocoDot.Name));
            }
            if (!configs.Any(c => c.PocoDot == relatedPocoDot))
            {
                throw new InvalidOperationException(SR.Get("Error.PocoConfigurationNotExist", relatedPocoDot.Name));
            }
            var config = new RelationConfiguration(mainPocoDot, relationship, relatedPocoDot, reversedRelationship, provider);
            configurator.Register(config);
            return configurator;
        }

        /// <summary>
        /// 获取一个指定的表示两个 PocoDot 的关系的配置信息的实例
        /// </summary>
        /// <param name="configurator">PocoDot 之间的关系的注册处的实例</param>
        /// <param name="mainPocoDot">指定的关系中的主 PocoDot的类型</param>
        /// <param name="relatedPocoDot">指定的关系中的从 PocoDot的类型</param>
        /// <returns>该指定的表示两个 PocoDot 的关系的配置信息的实例</returns>
        public static RelationConfiguration Get(this IRelationRegistrar configurator, Type mainPocoDot, Type relatedPocoDot)
        {
            var cfgs = from c in configurator.Configurations
                       where c.MainPocoDot == mainPocoDot
                       && c.RelatedPocoDot == relatedPocoDot
                       select c;
            if (cfgs.Count() == 1)
            {
                return cfgs.Single();
            }
            var errormsg = SR.Get("Error.MoreRelationConfigurationExists", mainPocoDot.Name, relatedPocoDot.Name);
            throw new InvalidOperationException(errormsg);
        }
    }
}
